package com.feeyo.prophet.actions.common;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.feeyo.llm.agent.engine.*;
import com.feeyo.prophet.pojo.action.functioncall.FunctionCall;
import com.feeyo.prophet.pojo.action.functioncall.ItemsBean;
import com.feeyo.prophet.pojo.action.functioncall.common.ChartOutputProperties;
import com.feeyo.prophet.pojo.action.functioncall.flight.common.BasicTypeDefaultList;
import com.feeyo.prophet.config.ParametersSingletonManager;
import com.feeyo.prophet.plugins.AnswerUtils;
import com.feeyo.prophet.plugins.ConstantUtils;
import com.feeyo.prophet.plugins.DbSearchActionUtils;
import com.feeyo.prophet.plugins.Md5Util;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.knowm.xchart.AnnotationText;
import org.knowm.xchart.BitmapEncoder;
import org.knowm.xchart.CategoryChart;
import org.knowm.xchart.CategoryChartBuilder;
import org.knowm.xchart.style.Styler;
import org.springframework.http.HttpStatus;

import java.awt.*;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 2024年2月份9C航司航班量与2022年同期相比变化趋势
 * 图表输出
 *
 * @author lihu
 */

@Slf4j
public class ChartOutputAction implements Action {

    private final String bucket;
    private final String riakLocalHost;

    public ChartOutputAction(String riakLocalHost, String bucket) {
        this.bucket = bucket;
        this.riakLocalHost = riakLocalHost;
    }

    @Override
    public String human() {
        return "图表输出";
    }

    @Override
    public String name() {
        return "ChartOutputAction";
    }

    @Override
    public String eg() {
        return """
                Action: ChartOutputAction
                Action Input: {"data":[{"name":"春秋航空客运航班量","type":"bar","value":[14442.0,14989.0,14722.0,14217.0,11075.0],"yAxisIndex":1}],"title":"航司数据趋势查询","type":"chart","xAxis":{"data":["2024-01","2024-02","2024-03","2024-04","2024-05"]},"yAxis":[{"formatter":"班","name":"春秋航空客运航班量"}]}
                """;
    }

    @Override
    public String description() {
        return """
                此工具用于给出趋势图、变化量图。当问及变化趋势或者直接追问图表给出数据时，可以使用此工具。注意此工具数据需要非常准确,不能假设数据。
                只能生成单指标图表。如果有多个指标，需要多次调用。
                """;
    }

    @Override
    public String parameters() {
        String parameters = ParametersSingletonManager.getParameters("ChartOutputAction", () -> {
            FunctionCall functionCall = new FunctionCall();
            functionCall.setType("object");
            functionCall.setRequired(Lists.newArrayList("title", "data", "xAxis"));
            ChartOutputProperties properties = new ChartOutputProperties();
            properties.setTitle(new BasicTypeDefaultList("string", "趋势图标题，是对趋势图内容的总结，不超过 20 个字。", "春秋航司上半年各月数据趋势图"));
            properties.setXAxis(new BasicTypeDefaultList("array", "X 轴数据值集合。例如：['2024-01', '2024-02', '2024-03', '2024-04', '2024-05']", new ItemsBean("string")));
            properties.setData(new BasicTypeDefaultList("array", "数据具体值数组，数组长度与 X 轴数组长度一致。例如：[14442.0, 14989.0, 14722.0, 14217.0, 11075.0]", new ItemsBean("number")));
            properties.setDataName(new BasicTypeDefaultList("string", "数据指标名称", "航班量"));
            functionCall.setProperties(properties);
            return functionCall.toString();
        });
        return parameters;
    }

    @Override
    public ParameterScheme defaultParameters() {
        Map<String, ParameterScheme.Property> properties = new HashMap<>();
        ParameterScheme.Property dataProperty = new ParameterScheme.Property();
        dataProperty.setType("array");
        dataProperty.setDescription("数据值集合，一组 Y 轴信息，仅能对应一组数据。例如：[{ \"name\": \"春秋航空客运航班量\", \"type\": \"bar\", \"value\": [14442.0, 14989.0, 14722.0, 14217.0, 11075.0], \"yAxisIndex\": 1 }]");
        ParameterScheme.Property.Items dataItems = new ParameterScheme.Property.Items();
        dataItems.setType("object");
        Map<String, ParameterScheme.Property> dataItemsProperties = new HashMap<>();
        dataItemsProperties.put("name", new ParameterScheme.Property("string", "数据列名称。例如：'春秋航空客运航班量'"));
        dataItemsProperties.put("type", new ParameterScheme.Property("string", "数据列格式。bar: 柱状图; line: 折线图。默认值为 'bar'。例如：'bar'", null, "bar", List.of("bar", "line"), null, null));
        dataItemsProperties.put("value", new ParameterScheme.Property("array", "数据具体值数组，数组长度与 X 轴数组长度一致。例如：[14442.0, 14989.0, 14722.0, 14217.0, 11075.0]", new ParameterScheme.Property.Items("number", null, null, null), null, null, null, null));
        dataItemsProperties.put("yAxisIndex", new ParameterScheme.Property("number", "从 1 开始，依次递增。例如：1", null, 1, List.of(1, 2, 3, 4, 5, 6), null, null));
        dataItems.setProperties(dataItemsProperties);
        dataItems.setRequired(List.of("name", "value", "yAxisIndex"));
        dataProperty.setItems(dataItems);
        properties.put("data", dataProperty);
        properties.put("title", new ParameterScheme.Property("string", "趋势图标题，是对趋势图内容的总结，不超过 20 个字。例如：'航司数据趋势查询'"));
        properties.put("type", new ParameterScheme.Property("string", "数据展示类型。chart: 图表; excel: 表格。默认值为 'chart'。例如：'chart'", null, "chart", List.of("chart", "excel"), null, null));
        ParameterScheme.Property xAxisProperty = new ParameterScheme.Property();
        xAxisProperty.setType("object");
        ParameterScheme.Property xAxisDataProperty = new ParameterScheme.Property("array", "X 轴数据值集合。例如：['2024-01', '2024-02', '2024-03', '2024-04', '2024-05']");
        xAxisDataProperty.setItems(new ParameterScheme.Property.Items("string", null, null, null));
        Map<String, ParameterScheme.Property> xAxisProperties = new HashMap<>();
        xAxisProperties.put("data", xAxisDataProperty);
        xAxisProperty.setItems(new ParameterScheme.Property.Items("string", null, xAxisProperties, List.of("data")));
        properties.put("xAxis", xAxisProperty);
        // YAxis property
        ParameterScheme.Property yAxisProperty = new ParameterScheme.Property();
        yAxisProperty.setType("array");
        yAxisProperty.setDescription("Y 轴信息。例如：[{ \"formatter\": \"班\", \"name\": \"春秋航空客运航班量\" }]");
        ParameterScheme.Property.Items yAxisItems = new ParameterScheme.Property.Items();
        yAxisItems.setType("object");
        Map<String, ParameterScheme.Property> yAxisItemsProperties = new HashMap<>();
        yAxisItemsProperties.put("formatter", new ParameterScheme.Property("string", "Y 轴单位。例如：'班'"));
        yAxisItemsProperties.put("name", new ParameterScheme.Property("string", "Y 轴数据列名称，与 data 对应索引下的 name 值一致。例如：'春秋航空客运航班量'"));
        yAxisItems.setProperties(yAxisItemsProperties);
        yAxisItems.setRequired(List.of("formatter", "name"));
        yAxisProperty.setItems(yAxisItems);
        properties.put("yAxis", yAxisProperty);
        // Create ParameterScheme object
        ParameterScheme parameterScheme = new ParameterScheme("object", List.of("data", "title", "xAxis", "yAxis"), properties);
        return parameterScheme;
    }

    @Override
    public ActionResult run(String question, String input, ExecuteOptions options) {
        AttachObj attachObj;
        try {
            // 将 JSON 字符串转换为 BarChart 对象
            String fileName = Md5Util.generate();
            jsonToChart(fileName, input);
            String fileUrl = riakLocalHost + "/" + fileName + "." + BitmapEncoder.BitmapFormat.PNG;
            log.info("riak数据存储url,{}", fileUrl);
            // 如果转换成功，返回正常结果
            attachObj = new AttachObj(AttachObj.Type.Chart, "图表数据查看", fileUrl);
        } catch (Exception e) {
            // 捕获 JSON 转换异常并返回错误信息
            String errorMessage = "Failed to parse JSON input: " + e.getMessage();
            log.error(errorMessage);
            return new ActionResult(HttpStatus.INTERNAL_SERVER_ERROR.value(), "解析发生错误，请思考后再调用？");
        }
        return AnswerUtils.subContentAnswer(this.name(), input, attachObj, "请对以下内容进行总结,数据如下:" + input);
    }

    // 加载字体
    public Font getCustomFont() throws Exception {
        InputStream is = getClass().getResourceAsStream("/fonts/wqmh.ttf");
        return Font.createFont(Font.TRUETYPE_FONT, is).deriveFont(Font.PLAIN, 16);
    }

    /**
     * 将 JSON 数据绘制为条形图并保存为图片
     *
     * @param jsonData JSON 数据
     */
    public String jsonToChart(String fileName, String jsonData) throws Exception {
        // 解析 JSON 数据
        JSONObject jsonObject = JSON.parseObject(jsonData);
        JSONArray xAxisArray = jsonObject.getJSONArray("xAxis");
        JSONArray dataArray = jsonObject.getJSONArray("data");
        String title = jsonObject.getString("title");
        String dataName = jsonObject.getString("dataName");
        // 创建图表
        CategoryChart chart = new CategoryChartBuilder().width(800).height(600)
                .title(title)
                .build();
        // 使用自定义字体
        Font font = getCustomFont();
        // 自定义图表样式
        chart.getStyler().setLegendPosition(Styler.LegendPosition.InsideNW);
        chart.getStyler().setHasAnnotations(true);
        chart.getStyler().setYAxisGroupPosition(0, Styler.YAxisPosition.Left);
        // 设置基础字体
        chart.getStyler().setBaseFont(font);
        chart.getStyler().setAxisTickLabelsFont(font);
        // 设置标题字体
        chart.getStyler().setChartTitleFont(font);
        // 设置图例字体
        chart.getStyler().setLegendFont(font);
        chart.getStyler().setToolTipFont(font);
        // 设置 X 轴数据
        List<String> xData = xAxisArray.toJavaList(String.class);
        // 添加数据到图表
        double maxYValue = 0;
        List<Number> yData = dataArray.toJavaList(Number.class);
        chart.addSeries(dataName, xData, yData);
        // 找到最大 Y 值
        for (Number y : yData) {
            if (y.doubleValue() > maxYValue) {
                maxYValue = y.doubleValue();
            }
        }
        // 左边
        double xPosition = 0.0;
        // 顶部稍微留点空隙
        double yPosition = maxYValue * 1.08;
        AnnotationText subtitle = new AnnotationText("SOURCE：VariFlight", xPosition, yPosition, false);
        chart.addAnnotation(subtitle);
        // 保存图表为图片
        return saveChartAsImage(fileName, chart);
    }

    /**
     * 图片存储
     */
    public String saveChartAsImage(String fileNameHead, CategoryChart chart) {
        String riakPreview = "";
        String fileName = fileNameHead + "." + BitmapEncoder.BitmapFormat.PNG;
        try {
            // 将图表保存到字节数组中
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            BitmapEncoder.saveBitmap(chart, baos, BitmapEncoder.BitmapFormat.PNG);
            byte[] imageBytes = baos.toByteArray();
            // 将字节数组存储到 Riak
            DbSearchActionUtils.riakSave(bucket, fileName, imageBytes, ConstantUtils.CONTENT_TYPE);
            riakPreview = DbSearchActionUtils.riakPreview(bucket, fileName);
            log.info("图片已上传到 Riak, 图片预览地址: {}", riakPreview);
        } catch (Exception e) {
            log.error("保存图片失败: {}", e.getMessage(), e);
        }
        return riakPreview;
    }
}
